import config from '../config/main';
import logger from 'log4js';
import util from 'util';

const ACCESS_FORMAT = '%s -- %s %s HTTP/%s, %s %s';

logger.configure(config.log4js);


function middleware(_app) {
    const app = _app;

    // init logger
    app.log = logger;
    app.accessLog = logger.getLogger('http');

    return function* dispatch(next) {
        // access log
        const req = this.request;
        const header = req.header;
        const nodeReq = this.req;

        const logText = util.format(
            ACCESS_FORMAT,
            req.ip,
            req.method,
            req.url,
            nodeReq.httpVersion,
            req.length || null,
            header['user-agent']
        );

        const startTime = +new Date();
        let endTime = startTime;
        let costTime = 0;

        app.accessLog.debug(logText);

        // init log
        this.log = app.log;

        try {
            yield next;

            endTime = +new Date();
            costTime = endTime - startTime;

            if (this.status >= 500) {
                app.accessLog.error('%s (%d) cost: %dms',
                    logText, this.status, costTime);
            } else if (this.status >= 400) {
                app.accessLog.warn('%s (%d) cost: %dms',
                    logText, this.status, costTime);
            } else {
                app.accessLog.debug('%s (%d) cost: %dms',
                    logText, this.status, costTime);
            }
        } catch (e) {
            endTime = +new Date();
            costTime = endTime - startTime;

            if (e instanceof Error) {
                this.status = e.status;
                this.body = e.message;

                app.accessLog.error('%s (%d) cost: %dms, exception:%s',
                        logText, this.res.statusCode, costTime, e.message);
            } else {
                app.accessLog.error('%s (%d) cost: %dms, exception:',
                        logText, this.res.statusCode, costTime, e);
            }
        }
    };
}

export default middleware;
